classdef KarplusStrongWindow < handle
    %%KARPLUSSTRONGGUI Dooku Synthesizer Karplus Strong window GUI class
    properties
        % Figure variables
        hfig;
        handles;

        % Instrument data
        Data;
    end
    
    properties (SetObservable)
        finish;
    end
    
    methods
        
        function obj = KarplusStrongWindow
            % Figure Load
            obj.hfig = hgload('KarplusStrongGUI.fig');
            obj.handles = guihandles(obj.hfig);
            
            % Callbacks Definitions
            set(obj.handles.instrumentWindow, 'CloseRequestFcn', @(src, event) finishSelect(obj, src, event));
            set(obj.handles.instrumentMenu, 'Callback', @(src, event) instrumentSelect(obj, src, event));
            set(obj.handles.attackEdit, 'Callback', @(src, event) attackChange(obj, src, event));
            set(obj.handles.sustainEdit, 'Callback', @(src, event) sustainChange(obj, src, event));
            set(obj.handles.positionEdit, 'Callback', @(src, event) positionChange(obj, src, event));
            set(obj.handles.directionEdit, 'Callback', @(src, event) directionChange(obj, src, event));
            set(obj.handles.attackSlider, 'Callback', @(src, event) attackSlider(obj, src, event));
            set(obj.handles.sustainSlider, 'Callback', @(src, event) sustainSlider(obj, src, event));
            set(obj.handles.positionSlider, 'Callback', @(src, event) positionSlider(obj, src, event));
            set(obj.handles.directionSlider, 'Callback', @(src, event) directionSlider(obj, src, event));
            set(obj.handles.uniformRad, 'Callback', @(src, event) randomnessSelect(obj, src, event));
            set(obj.handles.gaussianRad, 'Callback', @(src, event) randomnessSelect(obj, src, event));
            set(obj.handles.freqEdit, 'Callback', @(src, event) freqChange(obj, src, event));
            bg_image = imread('play.png');
            set(obj.handles.play, 'Callback', @(src, event) play(obj, src, event), 'CData', bg_image);
            
            obj.defaultVariables();
        end
        
        function defaultVariables(obj)
            obj.Data.name = 'Karplus Strong';
            obj.Data.instrument = [];
            obj.Data.instrumentInd = 1;
            obj.Data.attack = 0.5;
            obj.Data.sustain = 0.8;
            obj.Data.pickPosition = 0;
            obj.Data.pickDirection = 0;
            obj.Data.randomness = 'uniform';
            obj.Data.testFreq = 220;
        end
        
        function visible(obj)
            set(obj.hfig, 'Visible', 'on');
            set(obj.hfig, 'Windowstyle', 'modal');
        end
        
        function refreshWindow(obj, dataIn)
            obj.Data = dataIn;
            set(obj.handles.instrumentMenu, 'Value', obj.Data.instrumentInd);
            set(obj.handles.attackEdit, 'String', num2str(obj.Data.attack));
            set(obj.handles.attackSlider, 'Value', obj.Data.attack);
            set(obj.handles.sustainEdit, 'String', num2str(obj.Data.sustain));
            set(obj.handles.sustainSlider, 'Value', obj.Data.sustain);
            set(obj.handles.positionEdit, 'String', num2str(obj.Data.pickPosition));
            set(obj.handles.positionSlider, 'Value', obj.Data.pickPosition);
            set(obj.handles.directionEdit, 'String', num2str(obj.Data.pickDirection));
            set(obj.handles.directionSlider, 'Value', obj.Data.pickDirection);
            if strcmp(obj.Data.randomness, 'uniform')
                set(obj.handles.uniformRad, 'Value', 1);
                set(obj.handles.gaussianRad, 'Value', 0);
            else
                set(obj.handles.uniformRad, 'Value', 0);
                set(obj.handles.gaussianRad, 'Value', 1);
            end
            set(obj.handles.freqEdit, 'String', num2str(obj.Data.testFreq));
        end
        
        function instrumentData = saveData(obj)
            
        end
                
        function obj = instrumentSelect(obj, src, ~)
            obj.Data.instrumentInd = get(src, 'Value');
            instrStr = get(src, 'String');
            if obj.Data.instrumentInd == 1
                obj.Data.instrument = [];
            else
                obj.Data.instrument = wavread(strcat(char(instrStr(obj.Data.instrumentInd)), '.wav')); %#ok<DWVRD>
            end
            
        end
        
        function obj = attackChange(obj, ~, ~)
            attackAux = str2double(get(obj.handles.attackEdit, 'String'));
            if sum(isnan(attackAux)) || sum(attackAux < 0) ||  sum(attackAux > 1)
                errordlg('Attack coeficient must be a numeric value between 0 and 1.', 'Inconsistent error');
                set(obj.handles.attackEdit, 'String', obj.Data.attack);
            else
                obj.Data.attack = attackAux;
                set(obj.handles.attackSlider, 'Value', obj.Data.attack);
            end
        end
        
        function obj = sustainChange(obj, ~, ~)
            sustainAux = str2double(get(obj.handles.sustainEdit, 'String'));
            if sum(isnan(sustainAux)) || sum(sustainAux < 0) ||  sum(sustainAux > 1)
                errordlg('Sustain coeficient must be a numeric value between 0 and 1.', 'Inconsistent error');
                set(obj.handles.sustainEdit, 'String', obj.Data.sustain);
            else
                obj.Data.sustain = sustainAux;
                set(obj.handles.sustainSlider, 'Value', obj.Data.sustain);
            end
        end
        
        function obj = positionChange(obj, ~, ~)
            positionAux = str2double(get(obj.handles.positionEdit, 'String'));
            if sum(isnan(positionAux)) || sum(positionAux < 0) ||  sum(positionAux > 1)
                errordlg('Position coeficient must be a numeric value between 0 and 1.', 'Inconsistent error');
                set(obj.handles.positionEdit, 'String', obj.Data.pickPosition);
            else
                obj.Data.pickPosition = positionAux;
                set(obj.handles.positionSlider, 'Value', obj.Data.pickPosition);
            end
        end
        
        function obj = directionChange(obj, ~, ~)
            directionAux = str2double(get(obj.handles.directionEdit, 'String'));
            if sum(isnan(directionAux)) || sum(directionAux < 0) ||  sum(directionAux > 1)
                errordlg('Direction coeficient must be a numeric value between 0 and 1.', 'Inconsistent error');
                set(obj.handles.directionEdit, 'String', obj.Data.pickDirection);
            else
                obj.Data.pickDirection = directionAux;
                set(obj.handles.directionSlider, 'Value', obj.Data.pickDirection);
            end
        end
        
        function obj = attackSlider(obj, src, ~)
            obj.Data.attack = get(src, 'Value');
            set(obj.handles.attackEdit, 'String', obj.Data.attack);
        end
        
        function obj = sustainSlider(obj, src, ~)
            obj.Data.sustain = get(src, 'Value');
            set(obj.handles.sustainEdit, 'String', obj.Data.sustain);
        end
        
        function obj = positionSlider(obj, src, ~)
            obj.Data.pickPosition = get(src, 'Value');
            set(obj.handles.positionEdit, 'String', obj.Data.pickPosition);
        end
        
        function obj = directionSlider(obj, src, ~)
            obj.Data.pickDirection = get(src, 'Value');
            set(obj.handles.directionEdit, 'String', obj.Data.pickDirection);
        end
        
        function obj = randomnessSelect(obj, src, ~)
            if src
                set(src, 'Value', 1);
            end
            if get(obj.handles.uniformRad, 'Value')
                obj.Data.randomness = 'uniform';
            else
                obj.Data.randomness = 'gaussian';
            end
        end
        
        function obj = freqChange(obj, ~, ~)
            freqAux = str2double(get(obj.handles.freqEdit, 'String'));
            if sum(isnan(freqAux)) || sum(freqAux < 0)
                errordlg('Test frequency must be a positive numeric value.', 'Inconsistent error');
                set(obj.handles.freqEdit, 'String', obj.Data.testFreq);
            else
                obj.Data.testFreq = freqAux;
            end
        end
        
        function obj = play(obj, ~, ~)
            Fs=44100;
            
            y = Karplus_Strong(obj.Data.testFreq, 1, obj.Data, Fs);
            
            if ~isempty(obj.Data.instrument)
                y = conv(y, obj.Data.instrument);
            end
            y = y / max(abs(y)) * 0.95;
            
            sound(y, Fs);
        end        
        
        
        function obj = finishSelect(obj, ~, ~)
            obj.finish = 1;
            set(obj.hfig, 'Visible', 'off');
            set(obj.hfig, 'Windowstyle', 'normal');
        end
        
    end
    
end
            